
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.Naming;

public class MandelbrotServerImpl extends UnicastRemoteObject 
	implements MandelbrotServer {

	static final long serialVersionUID = 91875401948L;

	public static final int ITERACOES = 100;
	private String nome;

	public MandelbrotServerImpl(String nome) throws RemoteException {
		super();
		this.nome = nome;
	}

	/**
	 * Metodo de inicio
	 * @param args Argumentos linha de comando
	 */
	public static void main(String [] args) {
		// install RMI security manager
		System.setSecurityManager(new RMISecurityManager());

		// arg. 0 = rmi url
		if (args.length!=1) {
			System.err.println("Usage: MandelbrotServerImpl <server-rmi-url>");
			System.exit(-1);
		}

		try {  
			// name with which we can find it = user name
			String name = args[0];
			//create new instance
			MandelbrotServer server = new MandelbrotServerImpl(name);
			// register with nameserver
			Naming.rebind(name, server);
			System.out.println("Started MandelbrotServer, registered as " + name);
		}
		catch(Exception e) {
			e.printStackTrace();
			System.exit(-1);
		}
	}

	/**
	 * Desenha uma regiao especifica de um fractal mandelbrot
	 * @param width Largura total da renderizacao do mandelbrot
	 * @param height Altura total da renderizacao do mandelbrot
	 * @param section Posicao vertical do inicio da seccao desta parte
	 * @param offset Altura da seccao
	 * @param pReal Posicao central complexa no plano de gauss(parte real)
	 * @param pImag Posicao central complexa no plano de gauss(parte imag)
	 * @param zoom Nivel de zoom aplicado ao fractal
	 * @return A imagem renderizada desta parte
	 */
	public int[] renderRegion(int width, int height, int section, int offset, 
							double pReal, double pImag, double zoom) throws RemoteException {

		System.out.println(nome + ": 0x" + 
		section + " " + width + "x" + (section+offset));

		/* cria parte do fractal */
		int[] dados = new int[width*offset];

		/* manda pintar esse pedaco */
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < offset; y++) {
				dados[(width*y)+x] = 
					paintPixel(x, section+y, width, height, new Vetor2D(pReal, pImag), zoom);
			}
		}

		return dados;
	}

	/**
	 * Pinta um unico pixel do fractal mandelbrot
	 * @param x Posicao horizontal do pixel
	 * @param y Posicao vertical do pixel
	 * @param width Largura total da renderizacao do mandelbrot
	 * @param height Altura total da renderizacao do mandelbrot
	 * @param position Posicao central complexa no plano de gauss
	 * @param zoom Nivel de zoom aplicado ao fractal
	 * @return iteracoes para o pixel calculado
	 */
	private int paintPixel(int x, int y, int width, int height, 
							Vetor2D position, double zoom) {
		Vetor2D z = new Vetor2D();
		int n = 0;
		double a;

		for (; n < ITERACOES && z.comprimento() < 3; n++) {
			a = z.x * z.x - (z.y * z.y) + position.x
					+ ((x - (width/2)) / zoom);
			z.y = z.x * z.y * 2 + position.y + ((y - (height/2)) / zoom);
			z.x = a;
		}

		return n;
	}

}
